package com.bear.线性结构.队列;


import java.util.Scanner;

/**
 * <简述>    环形数组模拟队列
 * <详细描述>
 *
 * @author LiuShanshan
 * @version $Id$
 */
public class QueueTest{
    public static void main(String[] args) {
        // 测试
        System.out.println("测试数组模拟环形队列的案例~~~");
        //创建一个环形队列
        CirciQueue queue=new CirciQueue(5);// 说明设置4,其队列的有效数据最大是3
        char key ; //接收用户输入
        Scanner scanner=new Scanner(System.in);//
        boolean loop=true;
        //输出一个菜单
        while(loop){
            System.out.println("s(show):显示队列");
            System.out.println("e(exit):退出程序");
            System.out.println("a(add):添加数据到队列");
            System.out.println("g(get):从队列取出数据");
            System.out.println("h(head):查看队列头的数据");
            key=scanner.next().charAt(0);//接收一个字符
            switch(key){
                case's':
                    queue.show();
                    break;
                case'a':
                    System.out.println("输出一个数");
                    int value=scanner.nextInt();
                    queue.add(value);
                    break;
                case'g'://取出数据
                    try{
                        int res=queue.get();
                        System.out.printf("取出的数据是%d\n",res);
                    }catch(Exception e){
                        //TODO:handleexception
                        System.out.println(e.getMessage());
                    }break;
                case'e':
                    scanner.close();
                    loop = false;
                    break;
                default:
                    break;
            }
        }
        System.out.println("程序退出");
    }
}

// 环形队列
class CirciQueue{
    // 最大容量
    private int maxSize ;
    // 最下面数据的下标（包含开始元素），从0开始
    private int front;
    // 最上面数据的上标 + 1（不包含结束元素）， 从0开始
    private int real;
    // 环形数组
    private int[] queueArray;

    // 1、构造函数，赋值初始值
    CirciQueue(int maxSize){
        this.maxSize = maxSize;
        this.queueArray = new int[this.maxSize];

    }

    // 2、判断容器是否为空
    private boolean notEmpty(){
        return this.real == this.front;
    }

    // 3、容量是否已满
    private boolean notFull(){
        return (real + 1)% maxSize == front;
    }
    // 4、将数据放入环形数组中
    public void add(int i){
        if(notFull()){
            System.out.println("容器已满，请先消费");
        }else{
            // 数据放入
            this.queueArray[real] =i;
            // real向后移动，这里需要考虑取模(余)（如果real正好在最上面，而front不等于0,并且可以放值，那么就需要将real放在最下面）
            this.real = (real +1) % maxSize;      // 取模
        }
    }

    // 5、拿取数据  从下往上拿
    public  int get(){
        // 是否容器为空
        if(notEmpty()){
            System.out.println("容器为空，请添加数据");
            return -1;
        }
        int i = queueArray[front];
        front = (front +1) % maxSize;     // 取模
        return i;
    }

    // 显示环形队列中的值
    public  void show(){
        // 是否容器为空
        if(notEmpty()){
            System.out.println("容器为空，请添加数据");
        }else{
            // 循环次数为真实的有值的数据长度
            for(int i = front; i < front + getRealLength(); i ++){
                // 当前值，要取模
                int i1 = queueArray[i % maxSize];                          // 取模
                System.out.printf("queueArray[%s]的值为:%s", queueArray[i % maxSize], i1);
            }
        }

    }

    // 获取真实的长度
    private int getRealLength(){
        // real在front上面         todo 这一部分重点看  取模
        return (maxSize + real - front)% maxSize;
    }

}

